/*
 * Copyright 2004-2024 H2 Group. Multiple-Licensed under the MPL 2.0,
 * and the EPL 1.0 (https://h2database.com/html/license.html).
 * Initial Developer: H2 Group
 */
package org.h2.expression.function;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.apache.commons.lang.StringUtils;
import org.apache.hop.core.Const;
import org.apache.hop.core.Result;
import org.apache.hop.run.HopRun;
import org.h2.Driver;
import org.h2.engine.SessionLocal;
import org.h2.expression.Expression;
import org.h2.expression.TypedValueExpression;
import org.h2.value.DataType;
import org.h2.value.TypeInfo;
import org.h2.value.Value;
import org.h2.value.ValueNull;
import org.h2.value.ValueVarchar;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.Map;


import org.apache.hop.core.Const;
import org.apache.hop.core.Result;
import org.apache.hop.run.HopRun;

import static javax.xml.parsers.DocumentBuilderFactory.newInstance;

/**
 * A CONCAT or CONCAT_WS function.
 */
public final class PipFunction extends FunctionN {

    /**
     * CONCAT() (non-standard).
     */
    public static final int PIP = 0;

    /**
     * CONCAT_WS() (non-standard).
     */
    public static final int PIP_WS = PIP + 1;

    private static final String[] NAMES = { //
            "PIP", "PIP_WS" //
    };

    private final int function;
    //提供pip对象,可以通过sql查询,也能通过webApp查询
    private final static org.apache.hop.run.HopRun pipe = new HopRun();

    public PipFunction(int function) {
        this(function, new Expression[4]);
    }

    public PipFunction(int function, Expression... args) {
        super(args);
        this.function = function;
    }

    @Override
    public Value getValue(SessionLocal session) {
        if (args.length < 2) {
            return ValueVarchar.get("需要传递2个参数,第1个是pip名称,第2个是参数", session);
        }
        String pip = args[0].getValue(session).toString().trim();
        String param = args[1].getValue(session).toString().trim();
        String ret = PipFunction.runPipCmd(pip, param);
        return ValueVarchar.get(ret, session);
    }

    /**
     * 运行pip命令
     * 1:sql中执行;2:servlet的api中执行;3:pip的结果作为表,方便查询和连接不同的数据库或文件;4:agent里面可以调用pip
     *
     * @param pipName   pip文件的名字
     * @param jsonParam json的base64的参数
     * @return 返回json字符串
     */
    public static String runPipCmd(String pipName, String jsonParam) {
        StringBuilder url = new StringBuilder();
        String projectName = System.getProperty("HOP_PROJECT_HOME");
        if (StringUtils.isEmpty(projectName)) {
            projectName = "samples";
        }
        url.append("-prj ").append(projectName).append(" -r local -f ");
        url.append(Const.pkgDir).append("/config/projects/").append(projectName);
        //去掉前后2个单引号
        if (pipName.startsWith("'")) {
            pipName = pipName.substring(1, pipName.length() - 1);
        }
        if (jsonParam.startsWith("'")) {
            jsonParam = jsonParam.substring(1, jsonParam.length() - 1);
        }
        // add by bzm 如果是hwf工作流,就不需要增加.hpl后缀了
        if (!pipName.contains(".")) {
            pipName = pipName + ".hpl ";
        }
        if (!pipName.startsWith("/")) {
            pipName = "/" + pipName;
        }

        url.append(pipName);
        url.append(" --parameters=param=").append(jsonParam);

        //String url="-j samples -r local -f config/projects/samples/devlake/api/org_prj.hpl -p pdt=混合云";
        System.out.println("[log]pipe命令行:" + url);
        String[] param = url.toString().split(" ");
        //url="-j samples -r local -f D:/robot/robot/odata/config/projects/samples/devlake/api/org_prj.hpl -p pdt=混合云";
        String ret = "";
        try {
            PipFunction.pipe.initPipeSvr(param);
            Result re = PipFunction.pipe.runCmd(param);
            ret = re.getLogText();
            JsonObject jsonObject = JsonParser.parseString(ret).getAsJsonObject();
            jsonObject.addProperty("code", 200);
            jsonObject.addProperty("message", "ok");
            //LOG.info("[log]pipe命令行:"+ret);
            ret = jsonObject.toString();
        } catch (Exception e) {
            JsonObject jsonRet = new JsonObject();
            jsonRet.addProperty("code", 500);
            jsonRet.addProperty("message", e.getMessage());
            ret = jsonRet.toString();
        }
        System.out.println("[PipFunction.runPipCmd]ret=:" + ret);
        return ret;
    }

    /**
     * 测试pipe调用
     *
     * @param args 参数
     */
    public static void main(String[] args) {

        try {
            String originalJson = "{\"data\":[{\"error\":\"你好\",\"message\":\"ok\"}]}";
            // 解析JSON字符串为JsonObject
            JsonObject jsonObject = JsonParser.parseString(originalJson).getAsJsonObject();
            JsonArray jsonArray = jsonObject.getAsJsonArray("data");
            // 获取JSON对象的键
            JsonObject lsObject = jsonArray.get(0).getAsJsonObject();
            String header = String.join(",", lsObject.keySet());
            System.out.println(header);
            jsonObject.addProperty("code", 200);
            jsonObject.addProperty("message", "ok");
            //LOG.info("[log]pipe命令行:"+ret);
            String ret = jsonObject.toString();
            System.out.println(ret);
        } catch (Exception e) {
            JsonObject jsonRet = new JsonObject();
            jsonRet.addProperty("code", 500);
            jsonRet.addProperty("message", e.getMessage());
        }

    }

    @Override
    public Expression optimize(SessionLocal session) {
        boolean allConst = optimizeArguments(session, true);
        int i = 0;
        long extra = 0L;
        if (function == PIP_WS) {
            i = 1;
            extra = getPrecision(0);
        }
        long precision = 0L;
        int l = args.length;
        boolean f = false;
        for (; i < l; i++) {
            if (args[i].isNullConstant()) {
                continue;
            }
            precision = DataType.addPrecision(precision, getPrecision(i));
            if (extra != 0L && f) {
                precision = DataType.addPrecision(precision, extra);
            }
            f = true;
        }
        type = TypeInfo.getTypeInfo(Value.VARCHAR, precision, 0, null);
        if (allConst) {
            return TypedValueExpression.getTypedIfNull(getValue(session), type);
        }
        return this;
    }

    private long getPrecision(int i) {
        TypeInfo t = args[i].getType();
        int valueType = t.getValueType();
        if (valueType == Value.NULL) {
            return 0L;
        } else if (DataType.isCharacterStringType(valueType)) {
            return t.getPrecision();
        } else {
            return Long.MAX_VALUE;
        }
    }

    @Override
    public String getName() {
        return NAMES[function];
    }

}
